//! x86_64 architecture-specific syscall handling
//! SPDX-License-Identifier: MPL-2.0

const std = @import("std");
const SyscallReturn = @import("../return.zig").SyscallReturn;
const Context = @import("../context.zig").Context;

/// x86_64 system call numbers (subset)
pub const SyscallNum = enum(u64) {
    read = 0,
    write = 1,
    open = 2,
    close = 3,
    stat = 4,
    fstat = 5,
    lstat = 6,
    poll = 7,
    lseek = 8,
    mmap = 9,
    mprotect = 10,
    munmap = 11,
    brk = 12,
    rt_sigaction = 13,
    rt_sigprocmask = 14,
    rt_sigreturn = 15,
    ioctl = 16,
    pread64 = 17,
    pwrite64 = 18,
    readv = 19,
    writev = 20,
    access = 21,
    pipe = 22,
    select = 23,
    sched_yield = 24,
    mremap = 25,
    msync = 26,
    mincore = 27,
    madvise = 28,
    shmget = 29,
    shmat = 30,
    shmctl = 31,
    dup = 32,
    dup2 = 33,
    pause = 34,
    nanosleep = 35,
    getitimer = 36,
    alarm = 37,
    setitimer = 38,
    getpid = 39,
    sendfile = 40,
    socket = 41,
    connect = 42,
    accept = 43,
    sendto = 44,
    recvfrom = 45,
    sendmsg = 46,
    recvmsg = 47,
    shutdown = 48,
    bind = 49,
    listen = 50,
    getsockname = 51,
    getpeername = 52,
    socketpair = 53,
    setsockopt = 54,
    getsockopt = 55,
    clone = 56,
    fork = 57,
    vfork = 58,
    execve = 59,
    exit = 60,
    wait4 = 61,
    kill = 62,
    uname = 63,
    _,
};

/// CPU register state for system calls
pub const SyscallRegs = extern struct {
    rax: u64, // syscall number and return value
    rdi: u64, // arg0
    rsi: u64, // arg1
    rdx: u64, // arg2
    r10: u64, // arg3 (rcx is used by syscall instruction)
    r8: u64,  // arg4
    r9: u64,  // arg5
    
    // Additional registers that might be needed
    rcx: u64, // return address
    r11: u64, // saved flags
    rsp: u64, // stack pointer
    rbp: u64, // base pointer
};

/// Extract syscall arguments from registers
pub fn extract_args(regs: *const SyscallRegs) [6]u64 {
    return [_]u64{
        regs.rdi, // arg0
        regs.rsi, // arg1
        regs.rdx, // arg2
        regs.r10, // arg3
        regs.r8,  // arg4
        regs.r9,  // arg5
    };
}

/// Set return value in registers
pub fn set_return_value(regs: *SyscallRegs, value: u64) void {
    regs.rax = value;
}

/// Handle x86_64 system call entry
pub fn handle_syscall_entry(regs: *SyscallRegs, context: *Context) void {
    const syscall_num = regs.rax;
    const args = extract_args(regs);
    
    // Call the main syscall dispatcher
    const lib = @import("../lib.zig");
    const result = lib.handle_syscall(
        syscall_num,
        args[0], args[1], args[2], args[3], args[4], args[5],
        context,
    );
    
    // Set return value
    set_return_value(regs, result);
}

/// Validate syscall number for x86_64
pub fn is_valid_syscall(num: u64) bool {
    return switch (num) {
        0...399 => true, // Most Linux syscalls are in this range
        else => false,
    };
}

/// Get syscall name for debugging
pub fn get_syscall_name(num: u64) []const u8 {
    const syscall_num: SyscallNum = @enumFromInt(num);
    return @tagName(syscall_num);
}

/// Architecture-specific syscall validation
pub fn validate_syscall_args(num: u64, args: [6]u64) bool {
    _ = num;
    _ = args;
    // TODO: Add architecture-specific validation
    // For example, checking pointer alignment, valid address ranges, etc.
    return true;
}